package cn.caplike.demo.consistence.threadpool.and.blockingqueue.context.controller;

import cn.caplike.demo.consistence.threadpool.and.blockingqueue.context.entity.Inventory;
import cn.caplike.demo.consistence.threadpool.and.blockingqueue.context.service.InventoryService;
import cn.caplike.demo.consistence.threadpool.and.blockingqueue.core.Request;
import cn.caplike.demo.consistence.threadpool.and.blockingqueue.core.service.RequestAsyncProcessService;
import cn.caplike.demo.consistence.threadpool.and.blockingqueue.request.InventoryCacheRequest;
import cn.caplike.demo.consistence.threadpool.and.blockingqueue.request.InventoryDatabaseRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

/**
 * 主要测试
 * <ol>
 *     <li>所有的请求是否从缓存队列中走</li>
 *     <li>通过延迟数据的操作，看看读请求是否有等待</li>
 *     <li>读请求通过之后，相同的读请求是否直接返回</li>
 *     <li>读请求的数据是否从缓存中获取</li>
 * </ol>
 */
@RestController
@RequestMapping(value = "/inventory")
@Slf4j
public class InventoryController {

    private InventoryService inventoryService;
    private RequestAsyncProcessService requestAsyncProcessService;

    // ~ Autowired

    /**
     * 更新库存的数据记录
     * 1. 将更新数据的记录路由到指定的队列中
     * 2. 后台不断的将从队列中取值去处理
     */
    @PostMapping(value = "/update")
    public String updateInventory(@RequestBody Inventory inventory) {
        log.info("---> 请求更新数据 将更新数据的记录路由到指定的队列中");
        Request request = new InventoryDatabaseRequest(inventory, this.inventoryService);
        this.requestAsyncProcessService.route(request);
        return "success";
    }

    /**
     * 获取库存记录
     * 如果在在一定时间内获取不到数据，则直接从数据库中获取，并且数据写入到缓存中
     */
    @GetMapping(value = "/{id}")
    public Inventory get(@PathVariable("id") String id) throws InterruptedException {
        log.info("---> 获取库存记录：{}", id);
        Inventory inventory;
        Request request = new InventoryCacheRequest(id, this.inventoryService, Boolean.FALSE);
        this.requestAsyncProcessService.route(request);
        long startTime = System.currentTimeMillis();
        long waitTime = 0L;
        // 不断循环从缓存中获取数据
        // 如果在在一定时间内获取不到数据，则直接从数据库中获取，并且数据写入到缓存中
        while (waitTime <= 3000) {
            inventory = this.inventoryService.getCache(id);
            if (null != inventory) {
                log.info("---> 从缓存中获取到数据");
                return inventory;
            } else {
                Thread.sleep(20);
                waitTime = System.currentTimeMillis() - startTime;
            }
        }

        // 直接从数据库中获取数据
        inventory = this.inventoryService.selectById(id);
        if (null != inventory) {
            request = new InventoryCacheRequest(id, this.inventoryService, Boolean.TRUE);
            this.requestAsyncProcessService.route(request);
            return inventory;
        }
        return null;
    }

    @Autowired
    public void setInventoryService(InventoryService inventoryService) {
        this.inventoryService = inventoryService;
    }

    @Autowired
    public void setRequestAsyncProcessService(RequestAsyncProcessService requestAsyncProcessService) {
        this.requestAsyncProcessService = requestAsyncProcessService;
    }
}
